package eda.tests;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;

import eda.hashTable.HashTable;
import eda.hashTable.HashTableImpl;
import eda.util.ADTOverflowException;


public class TestHashProbeLinear {

	public class K {
		int hash;
		public K(int k) {
			hash = k;
		}
		
		@Override
		public int hashCode() {
			return hash;
		}
		
		@Override
		public String toString() {
			return ""+hash;
		}
	}
	
	HashTable<K, Object> table;
	
	@Before public void creatHashTableLinearProbe() {
		table = new HashTableImpl<K, Object>(-1);
	}
	
	@Test 
	public void testIsEmpty() throws Exception{
		
		Assert.assertTrue(table.isEmpty());
		
		for (int i = 0; i < 30; i++) {
			table.insert(new K(i), Integer.toString(i));
		}
		
		Assert.assertFalse(table.isEmpty());
		
	}
	
	@Test
	public void testFull() throws Exception{
		
		Assert.assertFalse(table.full());
		
		for (int i = 0; i < 100; i++) {
			table.insert(new K(i), Integer.toString(i));
		}
		
		// Fills all the cells of the table with elements
		Assert.assertTrue(table.full());
		
	}
	
	@Test
	public void testSize() throws Exception{
		
		Assert.assertEquals(0, table.size());
		
		for (int i = 0; i < 100; i++) {
			table.insert(new K(i), Integer.toString(i));
			Assert.assertEquals(i + 1, table.size());
		}
		
		Assert.assertTrue(table.full());
		
	}
	
	/**
	 * Esse teste tem por objetivo 
	 * a simples conferencia da adicao
	 * e da expancao da tabela 
	 */
	@Test public void testInsertionHashTableProbe() {
		for (int i = 0; i < 31; i++) {
			K key = new K(i);
			try{
				table.insert(key, "valor do objeto");		
				Assert.assertEquals(i+1, table.size());
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Esse teste tem o objetivo de verificar
	 * Se o algoritmo de insercao esta apto
	 * para alocacao de elementos
	 * mesmo que sua posicao esteja ocupada
	 */
	@Test public void test2InsertionHashTableProbe() {
		int size = 0;
		for (int i = 46; i < 60; i++) {  //ocupara posicoes de 15 a 30
			K key = new K(i);
			try{
				table.insert(key, "valor do objeto");		
				Assert.assertEquals(++size, table.size());
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		K key = new K(22); //todas as posicoes de 15 a 30
		                   //mas como ja estao ocupadas, 
		                   //o valor vai entrar em uma posicao anterior a 22
		String value = "elemento adicinado com sucesso";
		try{
			table.insert(key, value);		
			Assert.assertEquals(++size, table.size());
			Assert.assertEquals(value, table.search(key));
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Esse teste verifica o caso de adicao da mesma key
	 * Com valores diferentes 
	 */
	@Test public void test3InsertionHashTableProbe() throws ADTOverflowException{
		K key = new K(0); 
        
		String value = "values 1";
		String value2 = "values 2";
		
		table.insert(key, value);		
		table.insert(key, value2);		
		Assert.assertEquals(value2, table.search(key));
	}
	
	
	/**
	 * Verifica se a pesquisa por chave
	 * @throws ADTOverflowException
	 */
	@Test public void testSearch()throws ADTOverflowException{
		K key2 = new K(2); //hashLinear == 2
		String value2 = "value 2";
		K key3 = new K(3); //hashLinear == 3
		String value3 = "value 3";
		K key4 = new K(4); //hashLinear == 4
		String value4 = "value 4";
		table.insert(key2, value2);
		table.insert(key3, value3);
		table.insert(key4, value4);
		Assert.assertEquals(value2, table.search(key2));
		Assert.assertEquals(value3, table.search(key3));
		Assert.assertEquals(value4, table.search(key4));
	}
	
	
	/**
	 * Verifica se a pesquisa por chave
	 * em caso de chaves conflituosas
	 * @throws ADTOverflowException
	 */
	@Test public void test2Search()throws ADTOverflowException{
		K key2 = new K(2); //hashLinear 2
		String value2 = "value 2";
		K key3 = new K(33); //conflito! novo hashLinear == 3
		String value3 = "value 3";
		K key4 = new K(63); //conflito! novo hashLinear == 4
		String value4 = "value 4";
		table.insert(key2, value2);
		table.insert(key3, value3);
		table.insert(key4, value4);
		Assert.assertEquals(value2, table.search(key2));
		Assert.assertEquals(value3, table.search(key3));
		Assert.assertEquals(value4, table.search(key4));
	}
	
	
	
	/**
	 *Esse metodo verifica a situacao:
	 *adiciono o elemento 1 de hashLinear x
	 *adiciono o elemento 2 de hashLinear x
	 *resolvo conflito calculando novo hash y para elemento 2
	 *deleto o elemento 1
	 *pesquiso o elemento 2
	 *verifico se a pesquisa retorna valor esperado
	 */
	@Test public void test3Search()throws Exception{
		K key2 = new K(2); //hashLinear 2
		String value2 = "value 2";
		K key3 = new K(33); //conflito! novo hashLinear == 3
		String value3 = "value 3";
		
		table.insert(key2, value2);
		table.insert(key3, value3);
		table.remove(key2);
		Assert.assertEquals(value3, table.search(key3));
	}
	
}
